using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Globalization;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.Messages;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.Netflix.Data;
using MediaOwl.Netflix.NetflixServiceReference;
using MediaOwl.Netflix.Resources;

namespace MediaOwl.Netflix.ViewModels
{
    [Export(typeof(IWorkitem<NetflixViewModel>))]
    public sealed class MovieTitleHomeViewModel : Workitem<NetflixViewModel>
    {
        #region Fields
        private readonly INetflixDataRepository repository;
        private readonly IEventAggregator eventAggregator;

        #endregion

        #region Constructor
        [ImportingConstructor]
        public MovieTitleHomeViewModel([Import(AllowRecomposition = true)]INetflixDataRepository repository, IEventAggregator eventAggregator)
        {
            IsHomeScreen = true;
            Order = 0;
            this.repository = repository;
            this.eventAggregator = eventAggregator;
            DisplayName = Captions.MovieTitleHomeTitle;
            Titles = new BindableCollection<Title>();

            int ipp;
            ItemsPerPage = int.TryParse(NetflixDataAccess.DefaultPageSize, NumberStyles.Integer, CultureInfo.CurrentUICulture, out ipp) 
                ? ipp
                : 20;

            CurrentPage = 1;
        }

        #endregion

        #region Properties & Backingfields

        private BindableCollection<Title> titles;
        public BindableCollection<Title> Titles
        {
            get { return titles; }
            set
            {
                titles = value;
                NotifyOfPropertyChange(() => Titles);
            }
        }

        private Title selectedItem;
        public Title SelectedItem
        {
            get { return selectedItem; }
            set
            {
                selectedItem = value;
                NotifyOfPropertyChange(() => SelectedItem);
            }
        }

        private string searchText;
        public string SearchText
        {
            get { return searchText; }
            set
            {
                searchText = value;
                NotifyOfPropertyChange(() => SearchText);
                NotifyOfPropertyChange(() => CanSearchItems);
            }
        }

        public bool CanSearchItems
        {
            get
            {
                if (string.IsNullOrEmpty(SearchText))
                {
                    return false;
                }
                return true;
            }
        }

        public bool CanNext
        {
            get
            {
                return CurrentPage*ItemsPerPage < TotalResults;
            }
        }

        public bool CanPrevious
        {
            get
            {
                return CurrentPage > 1;
            }
        }

        private long totalResults;
        public long TotalResults
        {
            get { return totalResults; }
            private set
            {
                totalResults = value;
                NotifyOfPropertyChange(() => TotalResults);
                NotifyOfPropertyChange(() => CanNext);
                NotifyOfPropertyChange(() => CanPrevious);
            }
        }

        private int itemsPerPage;
        public int ItemsPerPage
        {
            get { return itemsPerPage; }
            set
            {
                itemsPerPage = value;
                NotifyOfPropertyChange(() => ItemsPerPage);
                NotifyOfPropertyChange(() => CurrentPage);
                NotifyOfPropertyChange(() => CanPrevious);
                NotifyOfPropertyChange(() => CanNext);
            }
        }

        private int currentPage;
        public int CurrentPage
        {
            get { return currentPage; }
            set
            {
                currentPage = value;
                NotifyOfPropertyChange(() => CurrentPage);
                NotifyOfPropertyChange(() => CanPrevious);
                NotifyOfPropertyChange(() => CanNext);
            }
        }

        public string SearchResultText
        {
            get
            {
                if (string.IsNullOrWhiteSpace(SearchText) && TotalResults == 0)
                    return string.Empty;

                long totalTemp = CurrentPage*ItemsPerPage > TotalResults ? TotalResults : CurrentPage*ItemsPerPage;

                //Results {0} to {1} of {2} are shown;
                var s = string.Format(Captions.SearchResultBaseText, 
                    (CurrentPage - 1) * ItemsPerPage + 1,
                    totalTemp, 
                    TotalResults);

                return string.IsNullOrWhiteSpace(SearchText)
                           ? s
                           : string.Format(Captions.SearchTermBaseText, SearchText) + " " + s;
            }
        }

        #endregion

        #region Methods

        public IEnumerator<IResult> SearchItems()
        {
            return Search();
        }

        public IEnumerator<IResult> SearchShortCut()
        {
            return IsActive && CanSearchItems ? Search() : null;
        }

        private IEnumerator<IResult> Search()
        {
            yield return Show.Busy(this);

            yield return repository.GetTitles(SearchText, (items, total) =>
                                                              {
                                                                  Titles.Clear();
                                                                  Titles.AddRange(items);
                                                                  TotalResults = total;
                                                              }, x => eventAggregator.Publish(new ErrorMessage(x)), CurrentPage, ItemsPerPage);

            NotifyOfPropertyChange(() => SearchResultText);

            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> Next()
        {
            CurrentPage++;
            return Search();
        }

        public IEnumerator<IResult> Previous()
        {
            CurrentPage--;
            return Search();
        }

        public IEnumerator<IResult> Open()
        {
            if (SelectedItem == null)
                yield break;

            yield return Show.Child<MovieTitleSingleViewModel>(Helper.GetScreenId(SelectedItem))
                .In(Parent)
                .Configured(a =>
                                {
                                    a.WithTitle(SelectedItem);
                                    SelectedItem = null;
                                });
        }

        #endregion
    }
}